Skip to content

Upgrade azureauth-cli to 0.9.4 with native Linux support#142

Draft
Copilot wants to merge 2 commits intomainfrom
copilot/update-azureauth-cli-to-0-9-4
Draft

Upgrade azureauth-cli to 0.9.4 with native Linux support#142
Copilot wants to merge 2 commits intomainfrom
copilot/update-azureauth-cli-to-0-9-4

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 27, 2026

Upgrades azureauth-cli from 0.8.4 to 0.9.4, which adds native Linux support outside of WSL. Updates all platform-detection logic to treat native Linux and WSL uniformly — calling azureauth directly rather than routing through azureauth.exe or npm exec.

Core Changes

  • node-azureauth/src/install.ts: Version bump to 0.9.4; Windows artifact renamed from win10-x64.zipwin-x64.zip; removed stale linux: "azureauth.exe" from AZUREAUTH_NAME_MAP
  • utils/is-wsl.ts: New isLinux() export — platform() === "linux" — covers both native Linux and WSL; isWsl() retained for telemetry
  • azureauth-command.ts: isWsl() + ["azureauth.exe"]isLinux() + ["azureauth"]
  • ado.ts: All isWsl() guards replaced with isLinux() (spawn-vs-exec, prompt-hint quoting)
  • is-supported-platform-and-architecture.ts: Added linux: ["x64", "arm64"]; removed redundant isWsl() || OR check

Before / After:

// Before: WSL-only special case, native Linux unsupported
memo = isWsl() ? ["azureauth.exe"] : npxAzureAuthCommand;

// After: both WSL and native Linux call azureauth directly
memo = isLinux() ? ["azureauth"] : npxAzureAuthCommand;

Note on DOWNLOAD_MAP: Linux releases ship as .deb packages, which the decompress dependency cannot extract. Linux users are expected to install azureauth via the system package (.deb) so it is available in PATH — consistent with how WSL worked previously.

References and Relevant Issues

azureauth-cli 0.9.4 release: https://github.com/AzureAD/microsoft-authentication-cli/releases/tag/0.9.4

Detailed Description of the Pull Request / Additional comments

Tests updated to mock isLinux (replacing isWsl), add clearMemo to beforeEach so each test gets a clean command memo, and assert spawnSync("azureauth", [...]) rather than the old npm-exec invocation path.

Validation Steps Performed

All 22 existing tests pass with no modifications to test counts or test logic — only mock targets and expected values updated to reflect new behavior.

PR Checklist

  • Tests added/passed
  • Documentation updated

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/repos/AzureAD/microsoft-authentication-cli/releases/tags/0.9.4
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node /home/REDACTED/work/_temp/ghcca-node/node/bin/node --enable-source-maps /home/REDACTED/work/_temp/copilot-developer-action-main/dist/index.js (http block)

If you need me to access, download, or install something from one of these locations, you can either:


⚡ Quickly spin up Copilot coding agent tasks from anywhere on your macOS or Windows machine with Raycast.

Copilot AI changed the title [WIP] Upgrade azureauth-cli to version 0.9.4 Upgrade azureauth-cli to 0.9.4 with native Linux support Mar 27, 2026
Copilot AI requested a review from jcreamer898 March 27, 2026 18:57
`ado`,
`pat`,
`--prompt-hint ${isWsl() ? options.promptHint : `"${options.promptHint}"`}`, // We only use spawn for WSL. spawn does not does not require prompt hint to be wrapped in quotes. exec does.
`--prompt-hint ${isLinux() ? options.promptHint : `"${options.promptHint}"`}`, // We only use spawn for Linux (includes WSL). spawn does not require prompt hint to be wrapped in quotes. exec does.

Check warning

Code scanning / CodeQL

Unsafe shell command constructed from library input Medium

This array element which depends on
library input
is later used in a
shell command
.

Copilot Autofix

AI 11 days ago

In general, the safest fix is to avoid going through the shell altogether and instead pass arguments as an array to a function like child_process.spawn/spawnSync or execFile. When that’s not possible, we should not manually build a single command string with interpolated values; instead, parse or quote arguments with a robust library such as shell-quote.

Here, the Linux path is already safe because it uses spawnSync(command[0], command.slice(1), ...) with a proper argument array. The unsafe part is the non‑Linux branch where we call exec(command.join(" "), { env }). The minimal, behavior‑preserving fix is:

  • Import spawnSync directly from "node:child_process" is already done.
  • Stop joining command into a single string in the non‑Linux branch.
  • Use spawnSync there as well (like the Linux path), passing the env from azureAuthCommand() and encoding "utf-8".
  • Remove the special quoting logic that embeds quotes into the --prompt-hint string for non‑Linux; instead, always pass --prompt-hint as two separate arguments, [ "--prompt-hint", options.promptHint ], which makes quoting unnecessary. This preserves functional behavior while avoiding shell interpretation.
  • Similarly, split other --flag value pairs into distinct array elements instead of interpolated --flag ${value} strings, reducing the chance of accidental changes if someone later reintroduces a join.

These changes are all confined to packages/ado-npm-auth-lib/src/azureauth/ado.ts, specifically around the command array construction and the else branch that currently calls exec.

Suggested changeset 1
packages/ado-npm-auth-lib/src/azureauth/ado.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/packages/ado-npm-auth-lib/src/azureauth/ado.ts b/packages/ado-npm-auth-lib/src/azureauth/ado.ts
--- a/packages/ado-npm-auth-lib/src/azureauth/ado.ts
+++ b/packages/ado-npm-auth-lib/src/azureauth/ado.ts
@@ -51,28 +51,31 @@
 
   const command = [
     ...authCommand,
-    `ado`,
-    `pat`,
-    `--prompt-hint ${isLinux() ? options.promptHint : `"${options.promptHint}"`}`, // We only use spawn for Linux (includes WSL). spawn does not require prompt hint to be wrapped in quotes. exec does.
-    `--organization ${options.organization}`,
-    `--display-name ${options.displayName}`,
-    ...options.scope.map((scope) => `--scope ${scope}`),
+    "ado",
+    "pat",
+    "--prompt-hint",
+    options.promptHint,
+    "--organization",
+    options.organization,
+    "--display-name",
+    options.displayName,
+    ...options.scope.flatMap((scope) => ["--scope", scope]),
   ];
 
   if (options.output) {
-    command.push(`--output ${options.output}`);
+    command.push("--output", options.output);
   }
 
   if (options.mode) {
-    command.push(`--mode ${options.mode}`);
+    command.push("--mode", options.mode);
   }
 
   if (options.domain) {
-    command.push(`--domain ${options.domain}`);
+    command.push("--domain", options.domain);
   }
 
   if (options.timeout) {
-    command.push(`--timeout ${options.timeout}`);
+    command.push("--timeout", options.timeout);
   }
 
   try {
@@ -93,10 +84,15 @@
       }
     } else {
       try {
-        result = await exec(command.join(" "), { env });
+        result = spawnSync(command[0], command.slice(1), {
+          encoding: "utf-8",
+          env,
+        });
 
-        if (result.stderr && !result.stdout) {
-          throw new Error(result.stderr);
+        if (result.status !== 0 || (result.stderr && !result.stdout)) {
+          throw new Error(
+            `Azure Auth failed with exit code ${result.status}: ${result.stderr}`,
+          );
         }
       } catch (error: any) {
         throw new Error(
EOF
@@ -51,28 +51,31 @@

const command = [
...authCommand,
`ado`,
`pat`,
`--prompt-hint ${isLinux() ? options.promptHint : `"${options.promptHint}"`}`, // We only use spawn for Linux (includes WSL). spawn does not require prompt hint to be wrapped in quotes. exec does.
`--organization ${options.organization}`,
`--display-name ${options.displayName}`,
...options.scope.map((scope) => `--scope ${scope}`),
"ado",
"pat",
"--prompt-hint",
options.promptHint,
"--organization",
options.organization,
"--display-name",
options.displayName,
...options.scope.flatMap((scope) => ["--scope", scope]),
];

if (options.output) {
command.push(`--output ${options.output}`);
command.push("--output", options.output);
}

if (options.mode) {
command.push(`--mode ${options.mode}`);
command.push("--mode", options.mode);
}

if (options.domain) {
command.push(`--domain ${options.domain}`);
command.push("--domain", options.domain);
}

if (options.timeout) {
command.push(`--timeout ${options.timeout}`);
command.push("--timeout", options.timeout);
}

try {
@@ -93,10 +84,15 @@
}
} else {
try {
result = await exec(command.join(" "), { env });
result = spawnSync(command[0], command.slice(1), {
encoding: "utf-8",
env,
});

if (result.stderr && !result.stdout) {
throw new Error(result.stderr);
if (result.status !== 0 || (result.stderr && !result.stdout)) {
throw new Error(
`Azure Auth failed with exit code ${result.status}: ${result.stderr}`,
);
}
} catch (error: any) {
throw new Error(
Copilot is powered by AI and may make mistakes. Always verify output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Upgrade azureauth-cli to the new version 0.9.4

3 participants